﻿package game.network.api.fb.core {

	import game.network.api.fb.data.*;
	import game.network.api.fb.net.*;
	import game.network.api.fb.utils.*;

	import flash.net.URLRequestMethod;
	import flash.utils.Dictionary;

	public class AbstractFacebook {

		protected var session:FacebookSession;
		protected var authResponse:FacebookAuthResponse;
		protected var oauth2:Boolean;
		protected var openRequests:Dictionary;
		protected var resultHash:Dictionary;
		protected var locale:String;
		protected var parserHash:Dictionary;

		public function AbstractFacebook ():void {
			openRequests = new Dictionary();
			resultHash = new Dictionary(true);
			parserHash = new Dictionary();
		}

		protected function get accessToken ():String {
			if ((oauth2 && authResponse != null) || session != null) {
				return oauth2 ? authResponse.accessToken : session.accessToken;
			} else {
				return null;
			}
		}

		protected function api (method:String, callback:Function = null, params:* = null, requestMethod:String = 'GET'):void {
			method = (method.indexOf('/') != 0) ?  '/'+method : method;

			if (accessToken) {
				if (params == null) {
					params = {};
				}
				if (params.access_token == null) {
					params.access_token = accessToken;
				}
			}

			var req:FacebookRequest = new FacebookRequest();

			if (locale) {
				params.locale = locale;
			}

			openRequests[req] = callback;

			req.call (FacebookURLDefaults.GRAPH_URL+method, requestMethod, handleRequestLoad, params);
		}

		protected function uploadVideo (method:String, callback:Function = null, params:* = null):void {

			method = (method.indexOf('/') != 0) ?  '/'+method : method;

			if (accessToken) {
				if (params == null) {
					params = {};
				}
				if (params.access_token == null) {
					params.access_token = accessToken;
				}
			}

			var req:FacebookRequest = new FacebookRequest();

			if (locale) {
				params.locale = locale;
			}

			openRequests[req] = callback;

			req.call (FacebookURLDefaults.VIDEO_URL+method, 'POST', handleRequestLoad, params);
		}

		protected function pagingCall (url:String, callback:Function):FacebookRequest {
			var req:FacebookRequest = new FacebookRequest();

			openRequests[req] = callback;

			req.callURL (handleRequestLoad, url, locale);

			return req;
		}

		protected function getRawResult (data:Object):Object {
			return resultHash[data];
		}

		protected function nextPage (data:Object, callback:Function = null):FacebookRequest {
			var req:FacebookRequest = null;
			var rawObj:Object = getRawResult(data);
			if (rawObj && rawObj.paging && rawObj.paging.next) {
				req = pagingCall(rawObj.paging.next,callback);
			} else if (callback != null) {
				callback (null, 'no page');
			}
			return req;
		}

		protected function previousPage (data:Object, callback:Function = null):FacebookRequest {
			var req:FacebookRequest = null;
			var rawObj:Object = getRawResult(data);
			if (rawObj && rawObj.paging && rawObj.paging.previous) {
				req = pagingCall(rawObj.paging.previous,callback);
			} else if (callback != null) {
				callback (null, 'no page');
			}
			return req;
		}

		protected function handleRequestLoad (target:FacebookRequest):void {
			var resultCallback:Function = openRequests[target];
			if (resultCallback === null) {
				delete openRequests[target];
			}

			if (target.success) {
				var data:Object = ('data' in target.data) ? target.data.data : target.data;
				resultHash[data] = target.data;
				if (data.hasOwnProperty("error_code")) {
					resultCallback (null, data);
				} else {
					if (parserHash[target] is IResultParser) {
						var p:IResultParser = parserHash[target] as IResultParser;
						data = p.parse(data);
						parserHash[target] = null;
						delete parserHash[target];
					}
					resultCallback (data, null);
				}
			} else {
				resultCallback (null, target.data);
			}

			delete openRequests[target];
		}

		protected function callRestAPI (methodName:String, callback:Function = null, values:* = null, requestMethod:String = 'GET'):void {

			if (values == null) {
				values = {};
			}
			
			values.format = 'json';

			if (accessToken) {
				values.access_token = accessToken;
			}

			if (locale) {
				values.locale = locale;
			}

			var req:FacebookRequest = new FacebookRequest();

			openRequests[req] = callback;

			if (parserHash[values["queries"]] is IResultParser) {
				var p:IResultParser = parserHash[values["queries"]] as IResultParser;
				parserHash[values["queries"]] = null;
				delete parserHash[values["queries"]];
				parserHash[req] = p;
			}

			req.call (FacebookURLDefaults.API_URL + '/method/' + methodName, requestMethod, handleRequestLoad, values);
		}

		protected function fqlQuery (query:String, callback:Function=null, values:Object=null):void {

			for (var n:String in values) {
				query = query.replace(new RegExp('\\{'+n+'\\}', 'g'), values[n]);
			}

			callRestAPI ('fql.query', callback, {query:query});
		}

		protected function fqlMultiQuery (queries:FQLMultiQuery, callback:Function=null, parser:IResultParser=null):void {

			parserHash[queries.toString()] = parser != null ? parser : new FQLMultiQueryParser();

			callRestAPI ('fql.multiquery', callback, {queries:queries.toString()});
		}

		protected function batchRequest (batch:Batch, callback:Function=null):void {
			if (accessToken) {
				var request:FacebookBatchRequest = new FacebookBatchRequest(batch,callback);
				resultHash[request] = true;
				request.call (accessToken);
			}
		}

		protected function deleteObject (method:String, callback:Function = null):void {
			var params:Object = {method:'delete'};
			api (method, callback, params, URLRequestMethod.POST);
		}

		protected function getImageUrl (id:String, type:String = null):String {
			return FacebookURLDefaults.GRAPH_URL + '/' + id + '/picture' + (type != null?'?type=' + type:'');
		}
	}
}